﻿using System;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Web.Routing;

namespace Infrastructure.Mvc.SeedWork.RouterExtension
{
    public class LowerCaseUrlRoute : Route
    {
        private static readonly string[] RequiredKeys = {"area", "controller", "action"};

        public LowerCaseUrlRoute(string url, IRouteHandler routeHandler)
            : base(url, routeHandler)
        {
        }

        public LowerCaseUrlRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
            : base(url, defaults, routeHandler)
        {
        }

        public LowerCaseUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
            IRouteHandler routeHandler)
            : base(url, defaults, constraints, routeHandler)
        {
        }

        public LowerCaseUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
            RouteValueDictionary dataTokens, IRouteHandler routeHandler)
            : base(url, defaults, constraints, dataTokens, routeHandler)
        {
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            lowerRouteValues(requestContext.RouteData.Values);
            lowerRouteValues(values);
            lowerRouteValues(Defaults);
            return base.GetVirtualPath(requestContext, values);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        private static void lowerRouteValues(RouteValueDictionary values)
        {
            foreach (string key in RequiredKeys)
            {
                if (values.ContainsKey(key) == false) continue;

                object value = values[key];
                if (value == null) continue;

                string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                if (string.IsNullOrEmpty(valueString)) continue;

                values[key] = valueString.ToLower();
            }

            string[] otherKyes = values.Keys
                .Except(RequiredKeys, StringComparer.InvariantCultureIgnoreCase)
                .ToArray();

            foreach (string key in otherKyes)
            {
                object value = values[key];
                values.Remove(key);
                values.Add(key.ToLower(), value);
            }
        }
    }
}